<template>
  <div>
    <edit-page-top
      :breads="breads"
      :show-submit="initialLoad"
      :disable-submit="!canEdit && initialLoad"
      :show-copy="id > 0 && initialLoad"
      :show-delete="id > 0 && initialLoad"
      :submit-loading="loading && initialLoad"
      :copy-link="copyLink"
      :small-copy="true"
      :small-delete="true"
      @submit="submit"
      @delete="deleteStager"
    >
      <template #extra-stuff>
        <tooltip-button
          v-if="id > 0 && initialLoad && isDownload(stager)"
          color="success"
          icon="fa-download"
          text="Download"
          @click="download(stager)"
        />
        <tooltip-button
          v-if="id > 0 && initialLoad && isOneLiner(stager)"
          color="success"
          icon="fa-paperclip"
          text="Copy To Clipboard"
          @click="copy(stager)"
        />
      </template>
    </edit-page-top>
    <div class="headers">
      <h3>{{ mode }} Stager</h3>
    </div>
    <error-state-alert
      v-if="errorState"
      :resource-id="id"
      resource-type="stager"
    />
    <v-card v-else style="padding: 10px">
      <info-viewer class="info-viewer" :info="stagerInfo" />
      <v-autocomplete
        v-model="selectedTemplate"
        :items="stagerTemplateIds"
        :loading="!reset"
        dense
        outlined
        label="Type"
        :readonly="!canEdit"
      />
      <v-row v-if="selectedTemplate">
        <v-col cols="6">
          <v-text-field
            v-model="stager.name"
            outlined
            dense
            label="Name"
            :readonly="!canEdit"
          />
        </v-col>
        <v-col cols="6">
          <v-subheader>
            A name for the stager. Leave blank for an autogenerated name.
          </v-subheader>
        </v-col>
      </v-row>
      <general-form
        v-if="reset"
        ref="generalform"
        v-model="form"
        :options="stagerOptions"
        :priority="formPriorities"
        :readonly="!canEdit"
      />
    </v-card>
  </div>
</template>

<script>
import InfoViewer from "@/components/InfoViewer.vue";
import GeneralForm from "@/components/GeneralForm.vue";
import ErrorStateAlert from "@/components/ErrorStateAlert.vue";
import EditPageTop from "@/components/EditPageTop.vue";
import * as downloadApi from "@/api/download-api";
import CopyMixin from "@/mixins/copy-stager";
import TooltipButton from "@/components/TooltipButton.vue";
import { useStagerStore } from "@/stores/stager-module";
import * as stagerApi from "@/api/stager-api";

export default {
  name: "StagerEdit",
  components: {
    InfoViewer,
    GeneralForm,
    ErrorStateAlert,
    EditPageTop,
    TooltipButton,
  },
  mixins: [CopyMixin],
  data() {
    return {
      stager: { options: {} },
      stagerTemplate: { options: {} },
      selectedTemplate: "",
      form: {},
      reset: true,
      loading: false,
      formPriorities: ["Listener", "Language"],
      errorState: false,
      initialLoad: false,
    };
  },
  computed: {
    stagerStore() {
      return useStagerStore();
    },
    stagerTemplateIds() {
      return this.stagerStore.templateIds;
    },
    isNew() {
      return this.$route.name === "stagerNew";
    },
    isCopy() {
      return this.$route.params.copy === true;
    },
    mode() {
      if (this.isCopy) return "Copy";
      if (this.isNew) return "New";
      return "View";
    },
    canEdit() {
      return true;
    },
    id() {
      return this.isCopy ? 0 : this.$route.params.id;
    },
    copyLink() {
      if (this.id > 0)
        return { name: "stagerNew", params: { copy: true, id: this.id } };
      return {};
    },
    stagerInfo() {
      if (!this.stagerTemplate) return {};
      const a = this.stagerTemplate;
      return {
        authors: a.authors,
        description: a.description,
        comments: a.comments,
      };
    },
    stagerOptions() {
      if (!this.isNew || this.isCopy) {
        // if its not new, set the options
        // iterate over the options in this.listener and set the values
        const options = {};
        Object.keys(this.stager.options).forEach((key) => {
          options[key] = { ...this.stagerTemplate.options[key] };
          options[key].value = this.stager.options[key];
        });
        return options;
      }

      // if its new, use the defaults from the template
      const { options } = this.stagerTemplate;
      if (!options) return {};

      // if the listener query param is set, set the listener to that
      if (this.$route.query.listener) {
        options.Listener.value = this.$route.query.listener;
      }
      return options;
    },
    breads() {
      return [
        {
          text: "Stagers",
          disabled: false,
          to: "/stagers",
          exact: true,
        },
        {
          text: this.breadcrumbName,
          disabled: true,
          to: "/stagers-edit",
        },
      ];
    },
    breadcrumbName() {
      if (this.isCopy) return "New";
      if (this.stager.name) return this.stager.name;
      if (this.id) return this.id;
      return "New";
    },
  },
  watch: {
    /**
     * When the type dropdown changes, we get the options for the new type.
     */
    selectedTemplate: {
      async handler(val) {
        const a = await stagerApi
          .getStagerTemplate(val)
          .catch((err) => this.$snack.error(`Error: ${err}`));
        if (a) {
          this.reset = false;

          this.stagerTemplate = a;
          await this.$nextTick();
          this.reset = true;
          this.initialLoad = true;
        }
      },
    },
    id(val) {
      if (val) {
        this.getStager(val);
      }
    },
  },
  mounted() {
    this.stagerStore.getStagerTemplates();

    if (!this.isNew || this.isCopy) {
      // using the route param id instad of this.id
      // since this.id is 0 for copies.
      this.getStager(this.$route.params.id);
    }

    if (this.$route.query.template) {
      this.selectedTemplate = this.$route.query.template;
    }
  },
  methods: {
    submit() {
      if (this.loading || !this.$refs.generalform.$refs.form.validate()) {
        return;
      }

      this.loading = true;
      if (this.id > 0) {
        stagerApi
          .updateStager(this.id, { name: this.stager.name, options: this.form })
          .then(() => {
            this.$snack.success("Stager updated");
            this.loading = false;
          })
          .then(() => {
            this.getStager(this.id);
          })
          .catch((err) => {
            this.$snack.error(`Error: ${err}`);
            this.loading = false;
          });
      } else {
        stagerApi
          .createStager(
            this.selectedTemplate,
            this.stager.name || this.randomName(),
            this.form,
          )
          .then(({ id }) => {
            this.$snack.success("Stager created");
            this.loading = false;
            this.$router.push({ name: "stagerEdit", params: { id } });
          })
          .catch((err) => {
            this.$snack.error(`Error: ${err}`);
            this.loading = false;
          });
      }
    },
    async deleteStager() {
      if (
        await this.$root.$confirm(
          "Delete",
          `Are you sure you want to delete stager ${this.form.StarkillerName}?`,
          { color: "red" },
        )
      ) {
        try {
          await this.stagerStore.deleteStager(this.id);
          this.$router.push({ name: "stagers" });
        } catch (err) {
          this.$snack.error(`Error: ${err}`);
        }
      }
    },
    getStager(id) {
      stagerApi
        .getStager(id)
        .then((data) => {
          this.stager = data;
          this.selectedTemplate = data.template;
        })
        .catch(() => {
          this.errorState = true;
        });
    },
    randomName() {
      return (Math.random() + 1).toString(36).substring(7);
    },
    isDownload(stager) {
      return stager.downloads && stager.downloads.length > 0;
    },
    isOneLiner(stager) {
      return stager.one_liner;
    },
    // later on we could display multiple files, but at the moment,
    // i think it makes sense to just get the last one.
    async copy(stager) {
      const lastIndex = stager.downloads.length - 1;
      return this.copyStager(
        await downloadApi.getDownloadAsText(stager.downloads[lastIndex].id),
      );
    },
    async download(stager) {
      const lastIndex = stager.downloads.length - 1;
      return downloadApi.getDownload(stager.downloads[lastIndex].id);
    },
  },
};
</script>

<style></style>
